package com.winchain.chainbill.bill.biz.contract.cmd;

import com.shell.bee.base.exception.UnCheckException;
import com.shell.bee.base.exception.UnCheckMsgException;
import com.shell.bee.base.utils.DateUtil;
import com.shell.bee.base.utils.MoneyUtil;
import com.shell.bee.base.utils.SpringContextUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.bee.contract.ContService;
import com.shell.bee.contract.ContTemplateHelper;
import com.shell.bee.contract.po.ContBas;
import com.shell.bee.contract.po.ContProt;
import com.shell.bee.contract.po.ContTmpl;
import com.shell.bee.esign.po.EsCust;
import com.shell.bee.esign.service.EsCustService;
import com.shell.bee.esign.service.EsignSealService;
import com.shell.bee.esign.service.EsignSignService;
import com.shell.bee.esign.vo.SingleSignVo;
import com.shell.bee.report.utils.FilePathHelper;
import com.shell.bee.report.utils.PdfUtils;
import com.shell.contract.vo.ContractResponseBodyVo;
import com.shell.contract.vo.ContractSponsorVo;
import com.shell.contract.vo.SignDocInfoVo;
import com.shell.feign.ContractApiFeign;
import com.shell.feign.PubProtocolFeign;
import com.shell.framework.command.CommandContext;
import com.shell.framework.command.ICommand;
import com.shell.framework.utils.SysDateUtil;
import com.shell.governor.modules.po.PubProtocol;
import com.timevale.esign.sdk.tech.bean.result.AddSealResult;
import com.timevale.esign.sdk.tech.bean.result.FileDigestSignResult;
import com.timevale.esign.sdk.tech.bean.seal.OrganizeTemplateType;
import com.timevale.esign.sdk.tech.bean.seal.SealColor;
import com.winchain.chainbill.ChainBillUtil;
import com.winchain.chainbill.basic.cus.po.CusRec;
import com.winchain.chainbill.basic.cus.service.CusRecService;
import com.winchain.chainbill.bill.base.po.CbDct;
import com.winchain.chainbill.bill.base.po.CbDfrl;
import com.winchain.chainbill.bill.base.po.CbRec;
import com.winchain.chainbill.bill.base.po.CbSnd;
import com.winchain.chainbill.bill.base.po.CbXfe;
import com.winchain.chainbill.bill.base.service.CbRecService;
import com.winchain.chainbill.bill.base.service.CbSndService;
import com.winchain.chainbill.bill.biz.Bill;
import com.winchain.chainbill.bill.biz.contract.keyword.EsignDctKeyword;
import com.winchain.chainbill.bill.biz.contract.keyword.EsignSndKeyword;
import com.winchain.chainbill.bill.biz.contract.keyword.EsignXfeKeyword;
import com.winchain.chainbill.esign.service.ContBasSnService;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ContractSponsorCmd<T> implements ICommand<Bill<T>> {
	@Autowired
	private ContractApiFeign contractApiFeign;
	@Autowired
	private CbSndService cbSndService;
	@Autowired
	private CbRecService cbRecService;
	@Autowired
	private ContService contService;
	@Autowired
	private PubProtocolFeign protocolFeign;
	@Autowired
	private CusRecService cusRecService;
	@Autowired
	private EsCustService esCustService;
	@Autowired
	private EsignSignService esignSignService;
	@Autowired
	private EsignSealService esignSealService;
	@Autowired
	private ContBasSnService contBasSnService;
	private static final String CREDIT_NM_KEY = "${creditNm}";

	public boolean execute(CommandContext<Bill<T>> context) throws Exception {
		if (!ChainBillUtil.signContOnline()) {
			createContForLocal(context);
		} else {
			if (ChainBillUtil.onCfca()) {
				createContForCfca(context);
			}
			if (ChainBillUtil.onEsign()) {
				createContForEsign(context);
			} else if ("on".equals(SpringContextUtil.getProperty("contract.switch"))) {
				createContractForHSL(context);
			}
		}
		return false;
	}

	private void createContForEsign(CommandContext<Bill<T>> context) {
		createContForLocal(context);
	}

	private void createContForCfca(CommandContext<Bill<T>> context) {
		createContForLocal(context);
	}

	private ContBas createContForLocal(CommandContext<Bill<T>> context) {
		Bill<T> bill = (Bill) context.getSource();
		CbRec rec = bill.getRec();
		T source = bill.getSource();
		String bizId = rec.getBillId();
		String bizType = null;
		String protTitle = null;
		String sponsorId = null;
		String acceptorId = null;
		String witness = null;
		String protocolType = null;
		String grpId = rec.getGrpId();
		String finId = "";
		CbDfrl cbDfrl = null;
		if (source == null) {
			return null;
		}
		if ((source instanceof CbSnd)) {
			bizType = "10";
			protTitle = "����";
			protocolType = "send_proto";
			CbSnd snd = (CbSnd) source;
			sponsorId = snd.getBuyerId();
			acceptorId = snd.getSellerId();
			witness = rec.getFinId();
		} else if ((source instanceof CbXfe)) {
			bizType = "11";
			protTitle = "����";
			protocolType = "transfer_proto";
			CbXfe xfe = (CbXfe) source;
			sponsorId = xfe.getBuyerId();
			acceptorId = xfe.getSellerId();
			cbDfrl = (CbDfrl) context.getValue("Deferral");
		} else if ((source instanceof CbDct)) {
			bizType = "12";
			protTitle = "����";
			protocolType = "discount_proto";
			CbDct dct = (CbDct) source;
			sponsorId = dct.getSellerId();
			acceptorId = dct.getFinId();
			finId = dct.getFinId();
		}
		CusRec cus = (CusRec) this.cusRecService.selectByKey(sponsorId);
		String contSn = this.contBasSnService.createContSn(cus.getGrpId());
		PubProtocol protocol = this.protocolFeign.getPubProtocolByTypeAndGrpId(protocolType, grpId, finId);
		List<ContTmpl> tmpls = this.contService.getContTmpl(bizType);
		List<ContProt> prots = null;
		if ((protocol != null) && (tmpls != null) && (tmpls.size() > 0)) {
			prots = new ArrayList();
			String oriContent = protocol.getContent();
			String content = genContent(oriContent, rec, source, bizType, cbDfrl, contSn);
			ContTmpl tmpl = (ContTmpl) tmpls.get(0);
			ContProt prot = this.contService.genProtWithContent(tmpl.getTmplId(), protTitle, content, true);

			prots.add(prot);
		}
		ContBas cont = new ContBas();
		String contId = SystemUtil.getUUID();
		cont.setContId(contId);
		cont.setContSn("");
		cont.setContTitle(protTitle);
		cont.setBizType(bizType);
		cont.setBizId(bizId);
		cont.setSponsor(sponsorId);
		cont.setAcceptor(acceptorId);
		cont.setWitness(witness);
		cont.setContDate(SysDateUtil.getSystemDate());
		cont.setCreateTime(SysDateUtil.getSystemDateTime());
		cont.setContSn(contSn);
		cont.setContState("1");
		cont.setContProgress("0");
		this.contService.saveCont(cont, prots);
		return cont;
	}

	private void signCreditor(ContProt prot, String oriContent, String creditId, String finId, String bizType) {
		String creditNmKey = "${creditNm}";
		if (oriContent.contains(creditNmKey)) {
			EsCust esCust = (EsCust) this.esCustService.selectByKey(creditId);
			if (esCust == null) {
				throw new UnCheckMsgException("��������������e��������");
			}
			String pdfSrcPath = prot.getProtLoc();
			String pdfDestPath = FilePathHelper.replaceFileName(pdfSrcPath, SystemUtil.getUUID(), "pdf");

			int appearTime = 1;
			if (("12".equals(bizType)) && (creditId.equals(finId))) {
				appearTime = 2;
			}
			Map<String, String> positon = PdfUtils.getKeyPosition(prot.getProtLoc(), esCust.getCustNm(), appearTime);
			String sealData = getCreidtSealData(esCust.getAcctId());
			SingleSignVo singleSignVo = new SingleSignVo();
			singleSignVo.setAcctId(esCust.getAcctId());
			singleSignVo.setSealData(sealData);
			singleSignVo.setSrcPdfPath(pdfSrcPath);
			singleSignVo.setDestPdfPath(pdfDestPath);
			singleSignVo.setContId(prot.getContId());
			singleSignVo.setCustId(creditId);
			singleSignVo.setSignPage((String) positon.get("page"));
			singleSignVo.setX((String) positon.get("X"));
			singleSignVo.setY((String) positon.get("Y"));
			FileDigestSignResult fileDigestSignResult = this.esignSignService.sign(singleSignVo);
			if (fileDigestSignResult.getErrCode() != 0) {
				throw new UnCheckMsgException("����������������������e������" + fileDigestSignResult.getMsg());
			}
			File tmp = new File(pdfSrcPath);
			if (tmp.exists()) {
				tmp.delete();
			}
			prot.setProtLoc(pdfDestPath);
		}
	}

	private String getCreidtSealData(String acctId) {
		AddSealResult seal = this.esignSealService.getOrganizeSeal(acctId, OrganizeTemplateType.STAR, SealColor.RED, "",
				"");
		return seal.getSealData();
	}

	private String genContent(String content, CbRec rec, T source, String bizType, CbDfrl cbDfrl, String contSn) {
		if ("10".equals(bizType)) {
			return genContent(content, rec, (CbSnd) source, contSn);
		}
		if ("11".equals(bizType)) {
			return genContent(content, rec, (CbXfe) source, cbDfrl, contSn);
		}
		return genContent(content, rec, (CbDct) source, contSn);
	}

	private String genContent(String content, CbRec rec, CbSnd snd, String contSn) {
		EsignSndKeyword keyword = new EsignSndKeyword();
		keyword.setBillAmt("��" + MoneyUtil.format(rec.getBillAmt()));
		keyword.setBillCode(rec.getBillCode());
		keyword.setBillExpDate(SysDateUtil.parseDate(rec.getExpDate(), "yyyyMMdd", "yyyy-MM-dd"));

		CusRec buyer = (CusRec) this.cusRecService.selectByKey(snd.getBuyerId());
		keyword.setBuyerNm(buyer.getCusName());
		keyword.setBuyerLegalNm(buyer.getLrName());
		keyword.setBuyerAddress(getCustAddress(buyer));
		keyword.setBuyerContactPhone(buyer.getContactorPhone());

		CusRec seller = (CusRec) this.cusRecService.selectByKey(snd.getSellerId());
		keyword.setOriginalSellerNm(seller.getCusName());
		keyword.setSellerLegalNm(seller.getLrName());
		keyword.setSellerAddress(getCustAddress(seller));
		keyword.setSellerContactPhone(seller.getContactorPhone());

		CusRec finner = (CusRec) this.cusRecService.selectByKey(rec.getFinId());
		keyword.setCreditNm(finner.getCusName());
		keyword.setCreditLegalNm(finner.getLrName());
		keyword.setCreditAddress(getCustAddress(finner));
		keyword.setCreditPhone(finner.getContactorPhone());
		keyword.setSendContSn(contSn);
		return ContTemplateHelper.replaceContent(content, keyword);
	}

	private String genContent(String content, CbRec rec, CbXfe xfe, CbDfrl dfrl, String contSn) {
		CbRec root = (CbRec) this.cbRecService.selectByKey(rec.getRootId());
		CbSnd snd = this.cbSndService.getBillSndById(root.getBillId());

		EsignXfeKeyword keyword = new EsignXfeKeyword();
		keyword.setBillAmt("��" + MoneyUtil.format(rec.getBillAmt()));
		keyword.setBillCode(rec.getBillCode());

		String expDate = rec.getExpDate();
		if (dfrl != null) {
			expDate = dfrl.getExpDate();
		}
		keyword.setBillExpDate(SysDateUtil.parseDate(expDate, "yyyyMMdd", "yyyy-MM-dd"));
		keyword.setRootBillCode(root.getBillCode());
		keyword.setRcvDate(SysDateUtil.parseDate(xfe.getXfeDate(), "yyyyMMdd", "yyyy-MM-dd"));
		keyword.setSellerNm2(snd.getBuyerNm());
		keyword.setBuyerNm(snd.getSellerNm());

		CusRec transfer = (CusRec) this.cusRecService.selectByKey(xfe.getBuyerId());
		keyword.setTransferNm(transfer.getCusName());
		keyword.setTransferLegalNm(transfer.getLrName());
		keyword.setTransferAddress(getCustAddress(transfer));
		keyword.setTransferContactPhone(transfer.getContactorPhone());
		if (("PERSONAL".equals(transfer.getCusType())) || ("SELF_EMPLOYED".equals(transfer.getCusType()))) {
			keyword.setTransferLegalNm(transfer.getContactorName());
		}
		CusRec seller = (CusRec) this.cusRecService.selectByKey(xfe.getSellerId());
		keyword.setSellerNm(seller.getCusName());
		keyword.setSellerLegalNm(seller.getLrName());
		keyword.setSellerAddress(getCustAddress(seller));
		keyword.setSellerContactPhone(seller.getContactorPhone());
		if (("PERSONAL".equals(seller.getCusType())) || ("SELF_EMPLOYED".equals(seller.getCusType()))) {
			keyword.setSellerLegalNm(seller.getContactorName());
		}
		CusRec finner = (CusRec) this.cusRecService.selectByKey(rec.getFinId());
		keyword.setCreditNm(finner.getCusName());
		keyword.setCreditLegalNm(finner.getLrName());
		keyword.setCreditAddress(getCustAddress(finner));
		keyword.setCreditPhone(finner.getContactorPhone());
		keyword.setTransferContSn(contSn);
		return ContTemplateHelper.replaceContent(content, keyword);
	}

	private String genContent(String content, CbRec rec, CbDct dct, String contSn) {
		CbRec root = (CbRec) this.cbRecService.selectByKey(rec.getRootId());
		CbSnd snd = this.cbSndService.getBillSndById(root.getBillId());
		CbRec parent;
		if (dct.getBillId().equals(dct.getPrntId())) {
			parent = rec;
		} else {
			parent = (CbRec) this.cbRecService.selectByKey(dct.getPrntId());
		}
		BigDecimal actualDctAmt = dct.getActualAmt();
		EsignDctKeyword keyword = new EsignDctKeyword();
		keyword.setBillAmt("��" + MoneyUtil.format(parent.getBillAmt()));
		keyword.setBillCode(parent.getBillCode());
		keyword.setDctInt("��" + MoneyUtil.format(dct.getDctInt()));
		keyword.setActualDctAmt("��" + MoneyUtil.format(actualDctAmt));
		keyword.setDctAmt("��" + MoneyUtil.format(dct.getDctAmt()));
		keyword.setDctRate(MoneyUtil.format(dct.getFixedRate().add(dct.getVarRate()).add(dct.getEntVarRate())) + "%");
		keyword.setDctDate(SysDateUtil.parseDate(dct.getDctDate(), "yyyyMMdd", "yyyy-MM-dd"));
		keyword.setDctDays(dct.getDctDays().toString() + "��");
		keyword.setBillExpDate(SysDateUtil.parseDate(rec.getExpDate(), "yyyyMMdd", "yyyy-MM-dd"));
		keyword.setSenderNm(snd.getBuyerNm());
		BigDecimal ratio = dct.getDctRatio();
		if (ratio == null) {
			keyword.setDctAmtRate("100%");
		} else {
			keyword.setDctAmtRate(ratio + "%");
		}
		CusRec discount = (CusRec) this.cusRecService.selectByKey(dct.getSellerId());
		keyword.setDctSellerNm(discount.getCusName() + " ");
		keyword.setDctSellerLegalNm(discount.getLrName());
		keyword.setDctSellerAddress(getCustAddress(discount));
		keyword.setDctSellerContactPhone(discount.getContactorPhone());
		if (("PERSONAL".equals(discount.getCusType())) || ("SELF_EMPLOYED".equals(discount.getCusType()))) {
			keyword.setDctSellerLegalNm(discount.getContactorName());
		}
		CusRec sellFinner = (CusRec) this.cusRecService.selectByKey(dct.getFinId());
		keyword.setFinNm(sellFinner.getCusName());
		keyword.setFinLegalNm(sellFinner.getLrName());
		keyword.setFinAddress(getCustAddress(sellFinner));
		keyword.setFinContactPhone(sellFinner.getContactorPhone());

		CusRec buyFinner = (CusRec) this.cusRecService.selectByKey(rec.getFinId());
		keyword.setCreditNm(buyFinner.getCusName());
		keyword.setCreditLegalNm(buyFinner.getLrName());
		keyword.setCreditAddress(getCustAddress(buyFinner));
		keyword.setCreditPhone(buyFinner.getContactorPhone());
		keyword.setDctContSn(contSn);
		return ContTemplateHelper.replaceContent(content, keyword);
	}

	private String getCustAddress(CusRec cusRec) {
		StringBuilder builder = new StringBuilder();
		if (StringUtil.notEmpty(cusRec.getProvince())) {
			builder.append(cusRec.getProvince());
		}
		if (StringUtil.notEmpty(cusRec.getCity())) {
			builder.append(cusRec.getCity());
		}
		builder.append(cusRec.getAddress());
		return builder.toString();
	}

	private void createContractForHSL(CommandContext<Bill<T>> context) {
		String contractBizType = null;
		String sponsorId = null;
		String acceptorId = null;
		String templateName = null;
		String title = null;
		Bill<T> bill = (Bill) context.getSource();
		CbRec rec = bill.getRec();
		T source = bill.getSource();
		Map<String, String> elements = new HashMap();

		String expDate = rec.getExpDate();
		if ((source instanceof CbSnd)) {
			CbSnd snd = (CbSnd) source;
			sponsorId = snd.getBuyerId();
			acceptorId = snd.getSellerId();
			contractBizType = "10";
			templateName = "snd_template";
			title = "����������������������";
			elements.put("sndDate", DateUtil.parseDate(rec.getSndDate(), "yyyyMMdd", "yyyy-MM-dd"));
		} else if ((source instanceof CbXfe)) {
			CbXfe xfe = (CbXfe) source;
			sponsorId = xfe.getBuyerId();
			acceptorId = xfe.getSellerId();
			contractBizType = "11";
			templateName = "xfe_template";
			title = "����������������������";
			elements.put("xfeDate", DateUtil.parseDate(xfe.getXfeDate(), "yyyyMMdd", "yyyy-MM-dd"));
			setRootBillInfo(elements, rec);

			expDate = xfe.getExpDate();
		} else if ((source instanceof CbDct)) {
			CbDct dct = (CbDct) source;
			sponsorId = dct.getSellerId();
			acceptorId = dct.getFinId();
			contractBizType = "12";
			templateName = "dct_template";
			title = "����������������������������������";
			setDctInfo(elements, dct);
		}
		elements.put("billAmt", MoneyUtil.format(rec.getBillAmt()));
		elements.put("billCode", rec.getBillCode());
		elements.put("expDate", DateUtil.parseDate(expDate, "yyyyMMdd", "yyyy-MM-dd"));
		if ((sponsorId != null) && (acceptorId != null)) {
			ContractSponsorVo contractSponsorVo = new ContractSponsorVo();
			contractSponsorVo.setBillId(bill.getRec().getBillId());
			contractSponsorVo.setBizType(contractBizType);
			contractSponsorVo.setDocId(SystemUtil.getUUID());
			contractSponsorVo.setDocTitle(title);
			contractSponsorVo.setSponsorId(sponsorId);
			contractSponsorVo.setAcceptorId(acceptorId);

			SignDocInfoVo signDocInfoVo = new SignDocInfoVo();
			signDocInfoVo.setTemplateName(templateName);
			signDocInfoVo.setIsView("1");
			signDocInfoVo.setTitle(title);
			signDocInfoVo.setElements(elements);
			signDocInfoVo.setBookmarks("");

			contractSponsorVo.setSignDocInfoVos(Arrays.asList(new SignDocInfoVo[] { signDocInfoVo }));
			ContractResponseBodyVo response = this.contractApiFeign.sponsor(contractSponsorVo);
			if (!response.isSuccess()) {
				throw new UnCheckException("��������������������: " + response.getErrorMsg());
			}
		}
	}

	private void setDctInfo(Map<String, String> elements, CbDct dct) {
		elements.put("dctRate", MoneyUtil.format(dct.getVarRate().add(dct.getFixedRate())));
		elements.put("dctDays", String.valueOf(dct.getDctDays()));
		elements.put("dctInt", MoneyUtil.format(dct.getDctInt()));
		elements.put("actAmt", MoneyUtil.format(dct.getDctAmt().subtract(dct.getDctInt())));
		elements.put("dctDate", DateUtil.parseDate(dct.getDctDate(), "yyyyMMdd", "yyyy-MM-dd"));
	}

	private void setRootBillInfo(Map<String, String> elements, CbRec rec) {
		String rootId = rec.getRootId();
		if (StringUtil.emptyAndNull(rec.getPrntId())) {
			rootId = rec.getBillId();
		}
		CbRec root = (CbRec) this.cbRecService.selectByKey(rootId);
		CbSnd snd = this.cbSndService.getBillSndById(rootId);
		elements.put("senderName", snd.getBuyerNm());
		elements.put("orignalHolderName", snd.getSellerNm());
		elements.put("rootCode", root.getBillCode());
	}
}
